package com.gitee.wsl.doc.prosemirror.model.node.ext

import com.gitee.wsl.doc.prosemirror.model.fragment.Slice
import com.gitee.wsl.doc.prosemirror.model.node.Node


// Finds a position at or around the given position where the given slice can be inserted. Will look
// at parent nodes' nearest boundary and try there, even if the original position wasn't directly at
// the start or end of that node. Returns null when no position was found.
@Suppress("NestedBlockDepth", "ComplexMethod")
fun Node.dropPoint(pos: Int, slice: Slice): Int? {
    val doc = this
    val thisPos = doc.resolve(pos)
    if (slice.content.size == 0) return pos
    var content = slice.content
    for (i in 0 until slice.openStart) {
        content = content.firstChild!!.content
    }
    var pass = 1
    while (pass <= (if (slice.openStart == 0 && slice.size != 0) 2 else 1)) {
        for (d in thisPos.depth downTo 0) {
            val bias =
                if (d == thisPos.depth) {
                    0
                } else if (thisPos.pos <= (thisPos.start(d + 1) + thisPos.end(d + 1)) / 2) {
                    -1
                } else {
                    1
                }
            val insertPos = thisPos.index(d) + (if (bias > 0) 1 else 0)
            val parent = thisPos.node(d)
            val fits: Boolean? = if (pass == 1) {
                parent.canReplace(insertPos, insertPos, content)
            } else {
                val wrapping = parent.contentMatchAt(insertPos).findWrapping(content.firstChild!!.type)
                wrapping?.let { parent.canReplaceWith(insertPos, insertPos, it.first()) }
            }
            if (fits == true) {
                return if (bias == 0) thisPos.pos else if (bias < 0) thisPos.before(d + 1) else thisPos.after(d + 1)
            }
        }
        pass++
    }
    return null
}